#pragma once


template <typename T>
class Vector2d
{
public:
	Vector2d() : 
		x(0),
		y(0)
	{}
	
	Vector2d(T xpos,T ypos) : 
		x(xpos),
		y(ypos)
	{}

	Vector2d(const Vector2d<T> &source) : 
		x(0),
		y(0)
	{
		if (this!=&source)
		{
			x=source.x;
			y=source.y;
		}
	}

	~Vector2d(){}

	inline bool operator==(const Vector2d<T>& source) const
	{
		return x == source.x && y == source.y;
	}

	inline bool operator!=(const Vector2d<T>& source) const
	{
		return x != source.x || y != source.y;
	}

	inline bool operator > (const Vector2d<T> &source) const
	{
		return (x == source.x) ? y > source.y : x > source.y;
	}

	inline bool operator < (const Vector2d<T> &source) const
	{
		return (x == source.x) ? y < source.y : x < source.x;
	}

	inline bool operator >= (const Vector2d<T> &source) const
	{
		return (x == source.x) ? y >= source.y : x >= source.x;
	}

	inline bool operator <= (const Vector2d<T> &source) const
	{
		return (x == source.x) ? y <= source.y : x <= source.x;
	}

	Vector2d<T>& operator=(const Vector2d<T> &source)
	{
		x=source.x;
		y=source.y;

		return *this;
	}

	inline Vector2d<T> operator+(const Vector2d<T>& source) const
	{
		return Vector2d<T>(x + source.x, y + source.y);
	}

	inline Vector2d<T> operator+=(const Vector2d<T>& source)
	{
		x += source.x; y += source.y; 
		return *this;
	}

	inline Vector2d<T> operator-(const Vector2d<T>& source) const
	{
		return Vector2d<T>(x - source.x, y - source.y);
	}

	inline Vector2d<T>& operator-=(const Vector2d<T>& source) 
	{
		x-=source.x;
		y-=source.y;
		return *this;
	}

	inline Vector2d<T> operator / (const Vector2d<T> &other) const
	{
		return Vector2d<T>(x / other.x, y / other.y);
	}

	inline Vector2d<T>& operator /= (const Vector2d<T> &other)
	{
		x /= other.x; y /= other.y;
		return *this;
	}

	inline Vector2d<T> operator / (T Size) const
	{
		return Vector2d<T>(x / Size, y / Size);
	}

	inline Vector2d<T>& operator /= (T Size)
	{
		x /= Size; y /= Size; 
		return *this;
	}

	inline Vector2d<T> operator*(const Vector2d<T>& source) const
	{
		return Vector2d<T>(x * other.x, y * other.y);	
	}

	inline Vector2d<T>& operator*=(const Vector2d<T>& source)
	{
		x *= source.x; y *= source.y; 
		return *this;
	}

	inline Vector2d<T> operator*(const T a) const
	{
		return Vector2d<T>(x * a, y * a);	
	}		

	inline Vector2d<T>& operator *= (T Size)
	{
		x *= Size; y *= Size; 
		return *this;
	}

	inline Vector2d<T> operator - () const
	{
		return Vector2d<T>(-X, -Y);
	}

	inline const T operator [] (unsigned int i) const
	{
		switch (i)
		{
		case 0: return x;
		case 1: return y;
		}
		return 0;
	}

	inline T& operator [] (unsigned int i)
	{
		return *(&x + i);
	}

	inline T Dot(const Vector2d<T> &other) const
	{
		return x*other.x + y*other.y;
	}

	inline T GetLength() const
	{
		return static_cast<T>( sqrt( static_cast<double>(x*x + y*y) ) );
	}
	inline T GetLengthSq() const
	{
		return x*x + y*y;
	}

	inline Vector2d<T>& SetAbs()
	{
		x = x > 0 ? x : -x;
		y = y > 0 ? y : -y;
		return *this;
	}
	inline Vector2d<T> GetAbs() const
	{
		return Vector2d<T>( (x > 0 ? x : -x), (y > 0 ? y : -y) );
	}

	inline void Set(T NewX, T NewY)
	{
		x = NewX; y = NewY;
	}
	inline void Get(T &NewX, T &NewY) const
	{
		NewX = x; NewY = y;
	}


	inline Vector2d<T>& GetCircleCollision(float ThisRadius, Vector2d<T> &OtherPoint, float OtherRadius)
	{
		float Distance = sqrt( (OtherPoint.x - x)*(OtherPoint.x - x) + (OtherPoint.y - y)*(OtherPoint.y - y) );
		float Degree = asin( (OtherPoint.x - x) / Distance )*180.0f/M_PI;

		if (y < OtherPoint.y)
			Degree = 180 - Degree;

		if (Distance < ThisRadius + OtherRadius)
		{
			OtherPoint.x = x + sin(Degree*M_PI/180) * (ThisRadius + OtherRadius);
			OtherPoint.y = y + cos(Degree*M_PI/180) * (ThisRadius + OtherRadius);
		}

		return OtherPoint;
	}

	inline bool IsPointInsideCircle(const Vector2d<T> &Center, const float Radius) const
	{
		return (x - Center.x)*(x - Center.x) + (y - Center.y)*(y - Center.y) < Radius*Radius;
	}

	inline T GetMin() const
	{
		return (x <= y) ? x : y;
	}
	inline T GetMax() const
	{
		return (x >= y) ? x : y;
	}

	inline bool IsNull()
	{
		if (!x && !y)
			return true;
		else
			return false;
	}	

	Vector2d<T> *MakeCopy()
	{
		return new Vector2d<T>(*this);
	}	

	T x,y;
};

typedef Vector2d<signed int> Vector2di;
typedef Vector2d<float> Vector2df;